/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package service

import (
	"strconv"
	"strings"

	"github.com/pkg/errors"

	"icep/bean/entity"
	"icep/bean/model"
	"icep/bean/param"
	"icep/common/constant"
	"icep/common/db"
	"icep/common/utils"
)

// QueryObtainEvidenceList 查询取证列表
func (is *IcepService) QueryObtainEvidenceList(userId string, queryPara param.ObtainListParam) (*db.Page, error) {
	args := make([]interface{}, 0)
	condition := "1 = 1"

	if userId == "" {
		return nil, errors.New("user id can not be empty")
	}
	combineSql(" and user_id = ? ", &condition, userId, &args)

	if queryPara.EvidenceName != "" {
		s := " and evidence_name like " + "'%" + queryPara.EvidenceName + "%' "
		combineSql(s, &condition, "", nil)
	}

	if queryPara.ObtainType != "" {
		combineSql(" and obtain_type = ? ", &condition, queryPara.ObtainType, &args)
	}

	if queryPara.StartTime != "" {
		condition = utils.StrJoin(condition, " and created_time >= ? ")
		args = append(args, queryPara.StartTime)
	}
	if queryPara.EndTime != "" {
		condition = utils.StrJoin(condition, " and created_time <= ? ")
		args = append(args, queryPara.EndTime)
	}

	pageSize := 10
	if queryPara.PageSize != "" {
		pageSize, _ = strconv.Atoi(queryPara.PageSize)
	}
	pageNo := 1
	if queryPara.PageNum != "" {
		pageNo, _ = strconv.Atoi(queryPara.PageNum)
	}
	page := db.NewPage(0, pageNo).SetPageSize(pageSize)

	var countEntity entity.IcepObtainEvidence
	count, err := is.DbEngine.Where(condition, args...).Count(&countEntity)
	if err != nil {
		return nil, errors.Errorf("query obtain evidence count error: %s", err)
	}
	page.SetTotal(count)

	evidenceList := make([]*entity.IcepObtainEvidence, 0)
	err = is.DbEngine.Where(condition, args...).Limit(pageSize, (pageNo-1)*pageSize).
		Desc("updated_time").Find(&evidenceList)
	if err != nil {
		return nil, errors.Errorf("query obtain evidence list error: %s", err)
	}

	obtainEvidenceList := make([]*model.ObtainEvidenceList, 0)
	for _, evidence := range evidenceList {
		obtainEvidenceList = append(obtainEvidenceList, &model.ObtainEvidenceList{
			EvidenceId:   evidence.Id,
			EvidenceName: evidence.EvidenceName,
			ObtainUrl:    evidence.ObtainUrl,
			Description:  evidence.Description,
			ObtainType:   evidence.ObtainType,
			Status:       evidence.Status,
			TxId:         evidence.TxId,
			TxTime:       evidence.TxTime,
			CreatedTime:  evidence.CreatedTime.Format(constant.TimeLayout),
			UpdatedTime:  evidence.UpdatedTime.Format(constant.TimeLayout),
		})
	}
	page.CreatePage(obtainEvidenceList)
	return page, nil
}

// QueryObtainEvidenceDetail 查询取证明细
func (is *IcepService) QueryObtainEvidenceDetail(currentTenantId, userId, evidenceId string) (*model.ObtainEvidenceDetail, error) {
	//取证表
	var evidence []*entity.IcepObtainEvidence
	err := is.DbEngine.Where("id = ?", evidenceId).Find(&evidence)
	if err != nil {
		return nil, errors.Errorf("query obtain evidence error: %s", err)
	}
	if len(evidence) == 0 {
		return nil, errors.New("evidenceId does not exist!")
	}
	res := model.ObtainEvidenceDetail{
		EvidenceId:   evidenceId,
		EvidenceName: evidence[0].EvidenceName,
		ObtainType:   evidence[0].ObtainType,
		TxId:         evidence[0].TxId,
		Status:       evidence[0].Status,
		EvidenceCert: evidence[0].EvidenceCert,
	}

	//取证明细
	var evidenceDetail []*entity.IcepObtainEvidenceDetail
	err = is.DbEngine.Where("obtain_id = ?", evidenceId).Find(&evidenceDetail)
	if err != nil {
		return nil, errors.Errorf("query obtain evidence detail error: %s", err)
	}

	if len(evidenceDetail) != 0 {
		var fileList []*model.ObtainEvidenceFile
		for _, data := range evidenceDetail {
			fileDesc := model.ObtainEvidenceFile{
				FileName: data.FileName,
				FileHash: data.FileHash,
				FileUrl:  data.FileUrl,
			}
			fileList = append(fileList, &fileDesc)
		}
		res.FileList = fileList
	}

	//签名表
	var signature []*entity.IcepSignature
	err = is.DbEngine.Where("evidence_id = ?", evidenceId).Find(&signature)
	if err != nil {
		return nil, errors.Errorf("query signature error: %s", err)
	}

	if len(signature) != 0 {
		res.Signature = signature[0].Signature
	}

	//用户表
	var user []*entity.IcepUser
	err = is.DbEngine.Where("id = ?", userId).Find(&user)
	if err != nil {
		return nil, errors.Errorf("query user error: %s", err)
	}
	res.PubKey = user[0].PubKey

	//根据交易id获取上链信息（区块哈希、区块号、交易内容等）
	if evidence[0].TxId != "" {
		//获取上链客户端
		chainClient := is.GetChainClient(currentTenantId)
		//根据交易id获取区块信息（区块号、区块哈希、前哈希）
		blockInfo := chainClient.GetBlockInfoById(evidence[0].TxId)
		if blockInfo != nil {
			res.BlockNum = blockInfo.BlockNum
			res.BlockHash = blockInfo.BlockHash
		}
		transInfo := chainClient.GetTransactionInfoById(evidence[0].TxId)
		if transInfo != nil {
			res.TxTime = transInfo.TxTime
			res.TxContent = transInfo.TxContent
			res.EvidenceData = getTotalHash(evidenceDetail)
		}
	}
	return &res, nil
}

// 按照文件顺序拼接哈希
func getTotalHash(data []*entity.IcepObtainEvidenceDetail) string {
	if len(data) == 1 {
		return data[0].FileHash
	}
	//多个文件排序后拼接哈希
	hashMap := make(map[int]string)
	for _, detail := range data {
		//以取证ID为分隔符切分fileUrl
		res := strings.Split(detail.FileUrl, detail.ObtainId+"/")
		if res == nil || len(res) != 2 {
			return ""
		}
		index, err := strconv.Atoi(res[1][0:1])
		if err != nil {
			return ""
		}
		//key为文件顺序, value为文件哈希
		hashMap[index] = detail.FileHash
	}

	filesHash := make([]string, 0)
	for i := 0; i < len(hashMap); i++ {
		filesHash = append(filesHash, hashMap[i+1])
	}
	return CombineHash(filesHash)
}
